﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Framework.Business;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;

namespace Framework.Helper
{
    public interface IMessageQueueHelper
    {
        void SendMessage<T>(T message);
        List<T> PullMessage<T>(int pullcount);
    }
    public class MessageQueueHelper: IMessageQueueHelper
    {
        private static volatile IConnection _connection;
        private static readonly object ConnectionLock = new object();
        static MessageQueueHelper()
        {
            InstanceManager.RegisterBuilder<IMessageQueueHelper, MessageQueueHelper>(
                () => new MessageQueueHelper());
        }

        private MessageQueueHelper()
        {
        }

        public static IMessageQueueHelper Instance
        {
            get
            {
                return InstanceManager.GetInstance<IMessageQueueHelper>();
            }
        }

        protected IConnection Connection
        {
            get
            {
                if (_connection != null)
                {
                    return _connection;
                }
                lock (ConnectionLock)
                {
                    if (_connection != null)
                    {
                        return _connection;
                    }
                    var connectionFactory = new ConnectionFactory
                    {
                        UserName = "admin",
                        Password = "admin",
                        HostName = "localhost",
                        //Port = 15672,
                        AutomaticRecoveryEnabled = true
                    };
                    _connection = connectionFactory.CreateConnection();
                }
                return _connection;
            }
        }

        private Dictionary<string, object> BuildQueueArgs()
        {
            Dictionary<string,object> args = new Dictionary<string, object>();

            args.Add("x-message-ttl", ConfigurationHelper.GetInteger("MessageTTL", 600000));

            return args;
        }

        private string MessageQueueName
        {
            get { return ConfigurationHelper.GetConfiguration("MQName", "InnomindQueue"); }
        }

        public void SendMessage<T>(T message)
        {
           var factory = new ConnectionFactory
           {
               HostName = ConfigurationHelper.GetConfiguration("MQHostName", "localhost"),
               UserName = ConfigurationHelper.GetConfiguration("MQUserName", "guest"),
               Password = ConfigurationHelper.GetConfiguration("MQPassword", "guest"),
               Port = AmqpTcpEndpoint.UseDefaultPort

           };
            using (var connection = factory.CreateConnection())
            {
                using (var publishChannel = connection.CreateModel())
                {
                    publishChannel.QueueDeclare(MessageQueueName, false, false, false, BuildQueueArgs());
                    var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
                    publishChannel.BasicPublish("", MessageQueueName, null, body);
                }
            }
        }

        public List<T> PullMessage<T>(int pullcount)
        {
            var factory = new ConnectionFactory
            {
                HostName = ConfigurationHelper.GetConfiguration("MQHostName", "localhost"),
                UserName = ConfigurationHelper.GetConfiguration("MQUserName", "guest"),
                Password = ConfigurationHelper.GetConfiguration("MQPassword", "guest"),
                Port = AmqpTcpEndpoint.UseDefaultPort
            };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    List<T> r = new List<T>();
                    for (int i = 0; i < pullcount; i++)
                    {
                        var data = channel.BasicGet(MessageQueueName, false);
                        if(null == data)
                            break;
                        var message = data.Body;
                        var re = Encoding.UTF8.GetString(message);
                        T result = JsonConvert.DeserializeObject<T>(re);
                        if (null != result)
                        {
                            r.Add(result);
                        }
                        channel.BasicAck(data.DeliveryTag, false);
                    }

                    return r;
                    //channel.QueueDeclare(MessageQueueName, false, false, false, BuildQueueArgs());
                    //channel.BasicQos(0, 10, false);

                    //var consumer = new QueueingBasicConsumer(channel);
                    //channel.BasicConsume(MessageQueueName, true, consumer);
                    //var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                    //var body = ea.Body;
                    //var message = Encoding.UTF8.GetString(body);
                }
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
            {
                return;
            }
            if (_connection == null)
            {
                return;
            }
            lock (ConnectionLock)
            {
                if (_connection == null)
                {
                    return;
                }
                _connection?.Dispose();
                _connection = null;
            }
        }
    }
}
